package com.xiao.libcore.result

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeoutException

sealed class XResult<out R>{

    data class Success<R>(val data:R):XResult<R>()

    data class Error(val error:Throwable):XResult<Nothing>(){
        fun message(): String{
            val msg: String
            when(error){
                is SocketTimeoutException->{
                    msg = "请检查网络"
                }
                is ConnectException ->{
                    msg = "请检查网络"
                }
                is UnknownHostException ->{
                    msg = "请检查网络"
                }
                is TimeoutException -> {
                    msg = "请检查网络"
                }
                else -> {
                    error.printStackTrace()
                    msg = error.message?:"请联系管理员"
                }
            }
            return msg
        }
    }

    data object Loading : XResult<Nothing>()

    fun isSuccess():Boolean{
        return this is Success
    }

    fun ifComplete(block: () -> Unit): XResult<R> {
        if (this is Success || this is Error){
            block()
        }
        return this
    }
    
    fun ifSuccess(block: (R) ->Unit): XResult<R> {
        if (this is Success){
            block(data)
        }
        return this
    }

    fun requireSuccess():R{
        return (this as Success).data
    }


    fun isError():Boolean{
        return this is Error
    }

    fun ifError(block: (Error) -> Unit): XResult<R> {
        if (this is Error){
            block(this)
        }
        return this
    }

    fun requireError(): Error {
        return (this as Error)
    }

}



suspend inline fun <R> withXResult(noinline block: suspend () -> R): XResult<R> {
    return try {
        val result = block()
        XResult.Success(result)
    } catch (e: Exception) {
        XResult.Error(e)
    }
}


fun <R> withXFlow( block: suspend () -> R): Flow<R> {
    return flow {
        try {
            val result = block()
            XResult.Success(result)
        }catch (e:Exception){
            XResult.Error(e)
        }
    }
}
